﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
using System.Collections.Specialized;
namespace Tracy.CoreLib.Data
{
    /// <summary>
    /// Tracy基本数据模型
    /// </summary>
    public abstract class XmlModel_BasicFunctions
    {
        #region 构造函数
        public XmlModel_BasicFunctions()
        {
        }
        public XmlModel_BasicFunctions(string xml)
        {
            LoadXml(xml);
        }
        public XmlModel_BasicFunctions(XmlNode node)
        {
            LoadXml(node);
        }
        #endregion

        #region 从Xml加载
        /// <summary>
        /// 加载Xml文档
        /// </summary>
        /// <param name="url">Xml文档所在位置</param>
        public virtual void Load(string url)
        {
            XmlReader reader = null;
            try
            {
                reader = XmlReader.Create(url);
                Load(reader);
            }
            finally
            {
                if (reader != null) reader.Close();
            }
        }

        /// <summary>
        /// 加载Xml文档
        /// </summary>
        public virtual void Load(XmlReader reader)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(reader);
            LoadXml(doc);
        }

        /// <summary>
        /// 加载Xml
        /// </summary>
        /// <param name="xml">字符串形式的Xml</param>
        public virtual void LoadXml(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            LoadXml(doc);
        }

        /// <summary>
        /// 加载Xml
        /// </summary>
        /// <param name="node">Xml节点</param>
        public virtual void LoadXml(XmlNode node)
        {
            if (this is IXmlModel)
            {
                if (node.Name != ((IXmlModel)this).XmlNodeName)//该节点的标签
                {
                    node = SelectNode(node, ((IXmlModel)this).XmlNodeName, true);
                }

                ParseXml(node);
            }
            else
            {
                throw new TracyException("未实现IXmlModel接口");
            }
        }

        protected virtual void ParseXml(XmlNode node)
        {
        }
        #endregion

        #region 导出到Xml

        /// <summary>
        /// 导出为Xml字符串
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        public virtual string ToXml(XmlDocument doc)
        {
            return ToXmlNode(doc).OuterXml;
        }

        /// <summary>
        /// 导出为Xml字符串
        /// </summary>
        /// <returns></returns>
        public virtual string ToXml()
        {
            XmlDocument doc = new XmlDocument();
            return ToXml(doc);
        }

        /// <summary>
        /// 导出为Xml节点
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        public virtual XmlNode ToXmlNode(XmlDocument doc)
        {
            if (this is IXmlModel)
            {
                XmlNode newNode = doc.CreateElement(((IXmlModel)this).XmlNodeName);//该节点的标签

                GenerateXml(doc, newNode);

                return newNode;
            }
            else
            {
                throw new TracyException("未实现IXmlModel接口");
            }
        }

        protected virtual void GenerateXml(XmlDocument doc, XmlNode newNode)
        {
        }
        #endregion

        #region 公用静态方法
        /// <summary>
        /// 从Xml中选取指定节点（匹配xpath表达式的第一个节点）
        /// </summary>
        /// <param name="node">有待查询的Xml</param>
        /// <param name="xpath">xpath表达式</param>
        /// <param name="mandatory">找不到节点是否抛出异常</param>
        protected static XmlNode SelectNode(XmlNode node, string xpath, bool mandatory)
        {

            XmlNode selectedNode = node.SelectSingleNode(xpath);
            if (mandatory && selectedNode == null) throw new TracyException(TracyException.EXCEPTION_XML_NODE_NOT_FOUND, xpath);
            return selectedNode;
        }

        /// <summary>
        /// 从Xml中选取指定节点（匹配xpath表达式的第一个节点）
        /// </summary>
        /// <param name="node">有待查询的Xml</param>
        /// <param name="xpath">xpath表达式</param>
        protected static XmlNode SelectNode(XmlNode node, string xpath)
        {
            return SelectNode(node, xpath, false);
        }

        /// <summary>
        /// 从Xml中选取指定节点（匹配xpath表达式的所有节点）
        /// </summary>
        /// <param name="node">有待查询的xml</param>
        /// <param name="xpath">xpath表达式</param>
        protected static XmlNodeList SelectNodes(XmlNode node, string xpath)
        {
            return node.SelectNodes(xpath);
        }

        /// <summary>
        /// 选取Xml节点的属性
        /// </summary>
        /// <param name="node">Xml节点</param>
        /// <param name="name">属性名称</param>
        /// <param name="mandatory">找不到节点是否抛出异常</param>
        protected static XmlNode SelectAttribute(XmlNode node, string name, bool mandatory)
        {
            XmlNode selectedNode = node.Attributes.GetNamedItem(name);
            if (mandatory && selectedNode == null) throw new TracyException(TracyException.EXCEPTION_XML_NODE_NOT_FOUND, name);
            return selectedNode;
        }

        /// <summary>
        /// 选取Xml节点的属性
        /// </summary>
        /// <param name="node">Xml节点</param>
        /// <param name="name">属性名称</param>
        protected static XmlNode SelectAttribute(XmlNode node, string name)
        {
            return SelectAttribute(node, name, false);
        }

        /// <summary>
        /// 为Xml节点添加子节点
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        /// <param name="node">Xml节点</param>
        /// <param name="name">子节点标签名称</param>
        /// <param name="value">子节点标签内的值</param>
        protected static XmlElement AppendTextChildNode(XmlDocument doc, XmlNode node, string name, string value)
        {
            XmlElement tmpChild = doc.CreateElement(name);
            tmpChild.InnerText = value;
            node.AppendChild(tmpChild);
            return tmpChild;
        }

        /// <summary>
        /// 为Xml节点添加属性
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        /// <param name="node">Xml节点</param>
        /// <param name="name">属性名称</param>
        /// <param name="value">属性值</param>
        protected static XmlAttribute AppendAttribute(XmlDocument doc, XmlNode node, string name, string value)
        {
            XmlAttribute tmpChild = doc.CreateAttribute(name);
            tmpChild.InnerText = value;
            node.Attributes.Append(tmpChild);
            return tmpChild;
        }
        #endregion
    }

    /// <summary>
    /// Tracy基本数据模型（自动导入导出）
    /// </summary>
    public abstract class XmlModel_AutoParseFunctions : XmlModel_BasicFunctions
    {
        #region 构造函数
        public XmlModel_AutoParseFunctions()
        {
        }
        public XmlModel_AutoParseFunctions(string xml)
        {
            LoadXml(xml);
        }
        public XmlModel_AutoParseFunctions(XmlNode node)
        {
            LoadXml(node);
        }
        #endregion

        private StringDictionary _data;
        /// <summary>
        /// 数据字典，维护各属性的值
        /// </summary>
        protected StringDictionary Data
        {
            get { if (_data == null)_data = new StringDictionary(); return _data; }
        }

        public virtual string GetValue(string key) { return Data[key]; }

        public virtual void SetValue(string key, string value) { Data[key] = value; }

        #region 从Xml加载

        protected override void ParseXml(XmlNode node)
        {
            PreParseXml(node); //子类的额外逻辑（导入前）

            GeneralImportData(node); //通用导入函数

            PostParseXml(node); //子类的额外逻辑（导入后）
        }

        /// <summary>
        /// 是否自动导入
        /// </summary>
        protected virtual bool AutoImportData
        {
            get { return true; }
        }

        /// <summary>
        /// 解析Xml节点并把属性导入到字典
        /// </summary>
        /// <param name="node">Xml节点</param>
        protected virtual void GeneralImportData(XmlNode node)
        {
            if (AutoImportData)
            {
                string tmpkey;

                string convertedNodeName = "";
                foreach (XmlNode value in node.ChildNodes)
                {
                    if (value.NodeType == XmlNodeType.Element)
                    {
                        //if (value.Name == Constants.CONST_TAG_DESCRIPTION) continue;//过滤掉Description信息
                        convertedNodeName = value.Name.Replace(":", "_colon_");//暂不支持namespace，将冒号转义
                        if (value.LastChild != null)//导入节点的值（该节点不含子节点）
                        {
                            if (value.LastChild.NodeType == XmlNodeType.Text || value.LastChild.NodeType == XmlNodeType.CDATA)
                            {
                                if (!Data.ContainsKey(convertedNodeName)) Data[convertedNodeName] = value.LastChild.Value;
                            }
                        }
                        if (value.Attributes != null)
                        {
                            foreach (XmlAttribute attr in value.Attributes)//导入属性
                            {
                                tmpkey = attr.Name + "@" + convertedNodeName;
                                if (!Data.ContainsKey(tmpkey)) Data[tmpkey] = attr.InnerText;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 加载Xml前的额外逻辑
        /// </summary>
        protected virtual void PreParseXml(XmlNode node)
        {

        }

        /// <summary>
        /// 加载Xml后的额外逻辑
        /// </summary>
        protected virtual void PostParseXml(XmlNode node)
        {

        }
        #endregion

        #region 导出到Xml

        protected override void GenerateXml(XmlDocument doc, XmlNode newNode)
        {
            PreGenerateXml(doc, newNode); //子类的额外逻辑（导出前）

            GeneralExportData(doc, newNode);//通用导出函数

            PostGenerateXml(doc, newNode);//子类的额外逻辑（导出后）
        }

        /// <summary>
        /// 是否自动导出
        /// </summary>
        protected virtual bool AutoExportData
        {
            get { return true; }
        }

        /// <summary>
        /// 将字典的内容导出到Xml节点
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        /// <param name="newNode">目标Xml节点</param>
        protected virtual void GeneralExportData(XmlDocument doc, XmlNode newNode)
        {
            if (AutoExportData)
            {
                string nodeName;
                string[] tmp;
                string tmpvalue = null;
                XmlNode newChildNode;
                foreach (string key in Data.Keys)
                {
                    tmp = key.Split('@');
                    nodeName = (tmp.Length > 1) ? tmp[1] : tmp[0];
                    if (Data.ContainsKey(nodeName)) tmpvalue = Data[nodeName];//如果节点也有值
                    newChildNode = SelectNode(newNode, nodeName);//如果节点已经创建，选择该节点
                    if (newChildNode == null) newChildNode = AppendTextChildNode(doc, newNode, nodeName, tmpvalue);//不然就新建该节点
                    if (tmp.Length > 1)
                    {
                        //添加属性
                        AppendAttribute(doc, newChildNode, tmp[0], Data[key]);
                    }
                }
            }
        }

        /// <summary>
        /// 导出前的额外逻辑
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        /// <param name="node">导出的Xml节点</param>
        protected virtual void PostGenerateXml(XmlDocument doc, XmlNode node)
        {

        }

        /// <summary>
        /// 导出后的额外逻辑
        /// </summary>
        /// <param name="doc">Xml节点所基于的XmlDocument</param>
        /// <param name="node">导出的Xml节点</param>
        protected virtual void PreGenerateXml(XmlDocument doc, XmlNode node)
        {

        }
        #endregion

        

        
    }

    //public class GeneralTracyModel : ManagedXmlModel, IManagedXmlModelItem
    //{

    //    #region IXmlModel Members
    //    private string _nodeName = "";
    //    public string XmlNodeName
    //    {
    //        get { return _nodeName; }
    //    }

    //    #endregion

    //    #region IKeyedItem Members

    //    public string Key
    //    {
    //        get { return Id.ToString(); }
    //    }
    //    #endregion

    //    public GeneralTracyModel(string nodeName):base()
    //    {
    //        _nodeName = nodeName;
    //    }
    //    public GeneralTracyModel(string nodeName, string xml)
    //        : base(xml)
    //    {
    //        _nodeName = nodeName;
    //    }
    //    public GeneralTracyModel(string nodeName, XmlNode node)
    //        : base(node)
    //    {
    //        _nodeName = nodeName;
    //    }
    //}
}
